package ca.scotthyndman.as2haxe.dom.binding.impl;

import ca.scotthyndman.as2haxe.dom.ASFieldAccess;
import ca.scotthyndman.as2haxe.dom.ASFunction;
import ca.scotthyndman.as2haxe.dom.ASMethodDeclaration;
import ca.scotthyndman.as2haxe.dom.ASName;
import ca.scotthyndman.as2haxe.dom.ASTNode;
import ca.scotthyndman.as2haxe.dom.ASTypeDeclaration;
import ca.scotthyndman.as2haxe.dom.binding.IMethodBinding;

/**
 * Represents a binding to a method.
 */
public class MethodBinding extends BindingBase implements IMethodBinding {

	public MethodBinding(ASTNode node, String key) {
		super(node, key);
	}

	public boolean overrides(IMethodBinding method) {
		// TODO implement this
		return false;
	}

	public BindingKind getKind() {
		return BindingKind.METHOD;
	}

	public String move(ASTNode newParent) throws Exception {
		if (!(newParent instanceof ASTypeDeclaration)) {
			throw new Exception("New parent for an ASFunction must be an "
					+ "ASTypeDeclaration");
		}

		ASFunction func = (ASFunction) getASTNode();
		ASTypeDeclaration type = (ASTypeDeclaration) newParent;

		if (log.isInfoEnabled()) {
			log.info("Moving function " + func.getName().toString()
					+ " to class " + type.getName().toString());
		}

		//
		// Rename the binding
		//
		String newName = type.getName().toString() + "."
				+ func.getName().toString();
		ASMethodDeclaration funcWrap = ((ASMethodDeclaration) func.getParent());
		((ASTypeDeclaration) funcWrap.getParent()).bodyDeclarations().remove(
				funcWrap);

		type.bodyDeclarations().add(funcWrap);

		//
		// Update the nodes
		//
		boolean isStatic = func.isStatic();

		for (ASTNode r : getReferringNodes()) {
			if (r instanceof ASFieldAccess) {
				ASFieldAccess fa = (ASFieldAccess) r;

				//
				// If the function is static, let's strip off the earlier
				// expressions and insert the type name
				//
				if (isStatic) {
					ASFieldAccess typeFa = ((ASName) type.getName().clone())
							.toFieldAccess();
					fa.setExpression(typeFa); // FIXME memory leak

					manager.link(typeFa);
				}

			}
		}
		
		return newName;
	}

}
